package mmc.resource.models.collada;

import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;

import java.util.List;

import mmc.EngineObject;

import static org.lwjgl.opengl.GL11.*;

import org.apache.xmlbeans.XmlCursor;
import org.collada.x2005.x11.colladaSchema.COLLADADocument;
import org.collada.x2005.x11.colladaSchema.InstanceControllerDocument.InstanceController;
import org.collada.x2005.x11.colladaSchema.InstanceGeometryDocument.InstanceGeometry;
import org.collada.x2005.x11.colladaSchema.NodeDocument.Node;

public class ColladaNode {
	
	List<Transform> transforms = new ArrayList<Transform>();
	List<ColladaGeometry> geometry = new ArrayList<ColladaGeometry>();
	List<ColladaSkinController> controller = new ArrayList<ColladaSkinController>();
	List<ColladaNode> nodes = new ArrayList<ColladaNode>();
	
	private static Map<String, ColladaNode> NODES = new TreeMap<String, ColladaNode>();
	
	public static ColladaNode loadNode(COLLADADocument doc, Node node){
		ColladaNode n = NODES.get(node.getId());
		
		if(n!=null)
			return n;
		
		n = new ColladaNode(doc, node);
		
		return n;
	}
	
	private ColladaNode(COLLADADocument doc, Node node){
		NODES.put(node.getId(), this);
		
		//load transformations
		XmlCursor cursor = node.newCursor();
		cursor.toChild(0);
		do{
			String type = cursor.getName().getLocalPart();
			Transform t = null;
			
			if(type.equals("rotate")){
				t = new RotateTransform(cursor.getTextValue());
			}else if(type.equals("translate")){
				t = new TranslateTransform(cursor.getTextValue());
			}else if(type.equals("scale")){
				t = new ScaleTransform(cursor.getTextValue());
			}else if(type.equals("instance_geometry")){
			}else if(type.equals("instance_controller")){
			}else if(type.equals("node")){
			}else{
				System.out.println("WARNING: ignoring "+type);
			}

			if(t!=null && t.isVital())
				transforms.add(t);
		}while(cursor.toNextSibling());
		cursor.dispose();
		
		//load static geometry
		for(InstanceGeometry g : node.getInstanceGeometryArray())
			geometry.add(new ColladaGeometry(doc, g));
		
		//load controlled geometry
		for(InstanceController c : node.getInstanceControllerArray()){
			controller.add(new ColladaSkinController(doc, c));
		}
		
		//load sub-nodes
		for(Node n : node.getNodeArray())
			nodes.add(new ColladaNode(doc,n));
	}
	
	public void render(EngineObject observer) {
		glPushMatrix();
		
		for(Transform t : transforms)
			t.apply();
		
		for(ColladaGeometry g : geometry)
			g.render(observer);
		
		for(ColladaSkinController c : controller)
			c.render(observer);
		
		for(ColladaNode n : nodes)
			n.render(observer);
		
		glPopMatrix();
	}
}

abstract class Transform{
	abstract void apply();
	abstract boolean isVital();
}

class RotateTransform extends Transform{

	float x,y,z,angle;
	
	public RotateTransform(String value){
		String[] s = value.split("\\ ");
		x = Float.parseFloat(s[0]);
		y = Float.parseFloat(s[1]);
		z = Float.parseFloat(s[2]);
		angle = Float.parseFloat(s[3]);
	}
	
	@Override
	void apply() {
		glRotatef(angle, x, y, z);
	}
	
	public boolean isVital(){
		return angle!=0;
	}
}

class TranslateTransform extends Transform{

	float x,y,z;
	
	public TranslateTransform(String value){
		String[] s = value.split("\\ ");
		x = Float.parseFloat(s[0]);
		y = Float.parseFloat(s[1]);
		z = Float.parseFloat(s[2]);
	}
	
	@Override
	void apply() {
		glTranslatef(x, y, z);
	}
	
	public boolean isVital(){
		return x+y+z!=0;
	}
}

class ScaleTransform extends Transform{

	float x,y,z;
	
	public ScaleTransform(String value){
		String[] s = value.split("\\ ");
		x = Float.parseFloat(s[0]);
		y = Float.parseFloat(s[1]);
		z = Float.parseFloat(s[2]);
	}
	
	@Override
	void apply() {
		glScalef(x, y, z);
	}
	
	public boolean isVital(){
		return x!=1||y!=1||z!=1;
	}
}